package org.jradweb.core.taglib;

import java.io.IOException;
import java.io.Reader;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;

import org.jradweb.core.utils.StringUtils;
import org.jradweb.core.web.FormBean;



public class OutTag extends BaseTag {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4863544994228510865L;
	private Object value;
	private int showLength=100;
	private boolean limitShowLength=true;
	private boolean escapeXml=true;
	private String def;
	private boolean needBody=false;
	private FormBean bean;
	private String property;
	
	
	public FormBean getBean() {
		return bean;
	}

	public void setBean(FormBean bean) {
		this.bean = bean;
	}

	public String getProperty() {
		return property;
	}

	public void setProperty(String property) {
		this.property = property;
	}

	public boolean isEscapeXml() {
		return escapeXml;
	}

	public void setEscapeXml(boolean escapeXml) {
		this.escapeXml = escapeXml;
	}

	public String getDefault() {
		return def;
	}

	public void setDefault(String def) {
		this.def = def;
	}

	public int getShowLength() {
		return showLength;
	}

	public void setShowLength(int showLength) {
		this.showLength = showLength;
	}

	public Object getValue() {
		return value;
	}

	public void setValue(Object value) {
		this.value = value;
	}
	
	
	
	@Override
	public int doStartTag() throws JspException {

	      needBody = false;			// reset state related to 'default'
	      this.bodyContent = null;  // clean-up body (just in case container is pooling tag handlers)
	      
	      try {
		// print value if available; otherwise, try 'default'
		if (value != null) {
	            out(pageContext, escapeXml, this.showLength,this.limitShowLength,value);
		    return SKIP_BODY;
		}else if(this.bean!=null&&this.property!=null){
			this.value=bean.getPropertyValueAsText(this.property);
			 out(pageContext, escapeXml, this.showLength,this.limitShowLength,value);			
			return SKIP_BODY;
		}
		else {
		    // if we don't have a 'default' attribute, just go to the body
		    if (def == null) {
			needBody = true;
			return EVAL_BODY_BUFFERED;
		    }

		    // if we do have 'default', print it
		    if (def != null) {
			// good 'default'
	                out(pageContext, escapeXml, this.showLength,this.limitShowLength,def);
		    }
		    return SKIP_BODY;
		}
	      } catch (IOException ex) {
		throw new JspException(ex.toString(), ex);
	      }
	    }

	@Override
	public int doEndTag() throws JspException {
		this.value=null;
		try {

			// trim and print out the body
			if (bodyContent != null && bodyContent.getString() != null)
				out(pageContext, escapeXml, this.showLength,this.limitShowLength,bodyContent.getString().trim());
			return EVAL_PAGE;
		} catch (IOException ex) {
			throw new JspException(ex.toString(), ex);
		}
	}
	
	private static String TRIMED_SUFFIX="...";
	public static void out(PageContext pageContext, boolean escapeXml,int showLength,boolean limitShowLength,
			Object obj) throws IOException {
		if(obj==null){
			return;
		}
		
		
		//处理String长度
		if(String.class.isInstance(obj)&&limitShowLength){
			String str=(String)obj;			
			if(StringUtils.getShowLenth(str)>showLength){
				String subString=StringUtils.getSubStringByShowLength(str, showLength);
				obj=subString+TRIMED_SUFFIX;
			}
		}
		
		
		JspWriter w = pageContext.getOut();
		if (!escapeXml) {
			// write chars as is
			if (obj instanceof Reader) {
				Reader reader = (Reader) obj;
				char[] buf = new char[4096];
				int count;
				while ((count = reader.read(buf, 0, 4096)) != -1) {
					w.write(buf, 0, count);
				}
			} else {
				w.write(obj.toString());
			}
		} else {
			// escape XML chars
			if (obj instanceof Reader) {
				Reader reader = (Reader) obj;
				char[] buf = new char[4096];
				int count;
				while ((count = reader.read(buf, 0, 4096)) != -1) {
					writeEscapedXml(buf, count, w);
				}
			} else {
				String text = obj.toString();
				writeEscapedXml(text.toCharArray(), text.length(), w);
			}
		}
	}

	/**
	 * 
	 * Optimized to create no extra objects and write directly to the JspWriter
	 * using blocks of escaped and unescaped characters
	 * 
	 */
	private static void writeEscapedXml(char[] buffer, int length, JspWriter w)
			throws IOException {
		int start = 0;

		for (int i = 0; i < length; i++) {
			char c = buffer[i];
			if (c <= org.apache.taglibs.standard.tag.common.core.Util.HIGHEST_SPECIAL) {
				char[] escaped = org.apache.taglibs.standard.tag.common.core.Util.specialCharactersRepresentation[c];
				if (escaped != null) {
					// add unescaped portion
					if (start < i) {
						w.write(buffer, start, i - start);
					}
					// add escaped xml
					w.write(escaped);
					start = i + 1;
				}
			}
		}
		// add rest of unescaped portion
		if (start < length) {
			w.write(buffer, start, length - start);
		}
	}

	public boolean isNeedBody() {
		return needBody;
	}

	public void setNeedBody(boolean needBody) {
		this.needBody = needBody;
	}

	public boolean isLimitShowLength() {
		return limitShowLength;
	}

	public void setLimitShowLength(boolean limitShowLength) {
		this.limitShowLength = limitShowLength;
	}

}
